﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Documents;
using System.Windows.Media;

namespace ZOIL.Library.Behaviors
{
    public class PluginObjectManipulationBehavior : PluginBehavior<FrameworkElement, ObjectManipulationBehavior>
    {
        #region private fields

        private AdornerLayer _adornerLayer;

        #endregion

        #region protected properties

        protected AdornerLayer AdornerLayer
        {
            get
            {
                if (_adornerLayer == null)
                {
                    var window = Window.GetWindow(AssociatedObject);

                    if (window != null)
                    {
                        var visual = window.Content as Visual;

                        if (visual != null)
                            _adornerLayer = AdornerLayer.GetAdornerLayer(visual);
                    }
                }
                return _adornerLayer;
            }
        }

        #endregion

        #region dependency properties

        #region IsResizable

        /// <summary>
        /// IsResizable Dependency Property
        /// </summary>
        public static DependencyProperty IsResizableProperty = DependencyProperty.RegisterAttached("IsResizable", typeof(bool), typeof(PluginObjectManipulationBehavior), new FrameworkPropertyMetadata(false, OnIsResizableChanged));

        /// <summary>
        /// Gets or sets the IsResizable property. This dependency property 
        /// indicates ....
        /// </summary>
        public bool IsResizable
        {
            get { return (bool)GetValue(IsResizableProperty); }
            set { SetValue(IsResizableProperty, value); }
        }

        /// <summary>
        /// Handles changes to the IsResizable property.
        /// </summary>
        private static void OnIsResizableChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var target = (PluginObjectManipulationBehavior)d;
            var oldIsResizable = (bool)e.OldValue;
            var newIsResizable = target.IsResizable;
            target.OnIsResizableChanged(oldIsResizable, newIsResizable);
        }

        /// <summary>
        /// Provides derived classes an opportunity to handle changes to the IsResizable property.
        /// </summary>
        protected virtual void OnIsResizableChanged(bool oldIsResizable, bool newIsResizable)
        {
        }

        #endregion

        #region IsRotatable

        /// <summary>
        /// IsRotatable Dependency Property
        /// </summary>
        public static DependencyProperty IsRotatableProperty = DependencyProperty.RegisterAttached("IsRotatable", typeof(bool), typeof(PluginObjectManipulationBehavior), new FrameworkPropertyMetadata(false, OnIsRotatableChanged));

        /// <summary>
        /// Gets or sets the IsRotatable property. This dependency property 
        /// indicates ....
        /// </summary>
        public bool IsRotatable
        {
            get { return (bool)GetValue(IsRotatableProperty); }
            set { SetValue(IsRotatableProperty, value); }
        }

        /// <summary>
        /// Handles changes to the IsRotatable property.
        /// </summary>
        private static void OnIsRotatableChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var target = (PluginObjectManipulationBehavior)d;
            var oldIsRotatable = (bool)e.OldValue;
            var newIsRotatable = target.IsRotatable;
            target.OnIsRotatableChanged(oldIsRotatable, newIsRotatable);
        }

        /// <summary>
        /// Provides derived classes an opportunity to handle changes to the IsRotatable property.
        /// </summary>
        protected virtual void OnIsRotatableChanged(bool oldIsRotatable, bool newIsRotatable)
        {
        }

        #endregion

        #region IsDraggable

        /// <summary>
        /// IsDraggable Dependency Property
        /// </summary>
        public static DependencyProperty IsDraggableProperty = DependencyProperty.RegisterAttached("IsDraggable", typeof(bool), typeof(PluginObjectManipulationBehavior), new FrameworkPropertyMetadata(false, OnIsDraggableChanged));

        /// <summary>
        /// Gets or sets the IsDraggable property. This dependency property 
        /// indicates ....
        /// </summary>
        public bool IsDraggable
        {
            get { return (bool)GetValue(IsDraggableProperty); }
            set { SetValue(IsDraggableProperty, value); }
        }

        /// <summary>
        /// Handles changes to the IsDraggable property.
        /// </summary>
        private static void OnIsDraggableChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var target = (PluginObjectManipulationBehavior)d;
            var oldIsDraggable = (bool)e.OldValue;
            var newIsDraggable = target.IsDraggable;
            target.OnIsDraggableChanged(oldIsDraggable, newIsDraggable);
        }

        /// <summary>
        /// Provides derived classes an opportunity to handle changes to the IsDraggable property.
        /// </summary>
        protected virtual void OnIsDraggableChanged(bool oldIsDraggable, bool newIsDraggable)
        {
        }

        #endregion

        #region IsDragging

        /// <summary>
        /// IsDragging Dependency Property
        /// </summary>
        public static DependencyProperty IsDraggingProperty = DependencyProperty.RegisterAttached("IsDragging", typeof(bool), typeof(PluginObjectManipulationBehavior), new FrameworkPropertyMetadata(false, OnIsDraggingChanged));

        /// <summary>
        /// Gets or sets the IsDragging property. This dependency property 
        /// indicates ....
        /// </summary>
        public bool IsDragging
        {
            get { return (bool)GetValue(IsDraggingProperty); }
            set { SetValue(IsDraggingProperty, value); }
        }

        /// <summary>
        /// Handles changes to the IsDragging property.
        /// </summary>
        private static void OnIsDraggingChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var target = (PluginObjectManipulationBehavior)d;
            var oldIsDragging = (bool)e.OldValue;
            var newIsDragging = target.IsDragging;
            target.OnIsDraggableChanged(oldIsDragging, newIsDragging);
        }

        /// <summary>
        /// Provides derived classes an opportunity to handle changes to the IsDragging property.
        /// </summary>
        protected virtual void OnIsDraggingChanged(bool oldIsDragging, bool newIsDragging)
        {
        }

        #endregion

        #region IsInertiaEnabled

        public bool IsInertiaEnabled
        {
            get { return (bool)GetValue(IsInertiaEnabledProperty); }
            set { SetValue(IsInertiaEnabledProperty, value); }
        }

        // Using a DependencyProperty as the backing store for IsInertiaEnabled.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty IsInertiaEnabledProperty =
            DependencyProperty.Register("IsInertiaEnabled", typeof(bool), typeof(PluginObjectManipulationBehavior), new PropertyMetadata(true, OnIsInertiaEnabledChanged));

        /// <summary>
        /// Handles changes to the IsDragging property.
        /// </summary>
        private static void OnIsInertiaEnabledChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var target = (PluginObjectManipulationBehavior)d;
            var oldIsInertiaEnabled = (bool)e.OldValue;
            var newIsInertiaEnabled = target.IsDragging;
            target.OnIsInertiaEnabledChanged(oldIsInertiaEnabled, newIsInertiaEnabled);
        }

        /// <summary>
        /// Provides derived classes an opportunity to handle changes to the IsDragging property.
        /// </summary>
        protected virtual void OnIsInertiaEnabledChanged(bool oldIsInertiaEnabled, bool newIsInertiaEnabled)
        {
        }

        #endregion

        #endregion

        #region overrides

        protected override void OnParentBehaviorChanged(ObjectManipulationBehavior oldParentBehavior, ObjectManipulationBehavior newParentBehavior)
        {
            CreateOneWayParentBehaviorBinding(ObjectManipulationBehavior.IsResizableProperty, IsResizableProperty);
            CreateOneWayParentBehaviorBinding(ObjectManipulationBehavior.IsRotatableProperty, IsRotatableProperty);
            CreateOneWayParentBehaviorBinding(ObjectManipulationBehavior.IsDraggableProperty, IsDraggableProperty);
            CreateTwoWayParentBehaviorBinding(ObjectManipulationBehavior.IsDraggingProperty, IsDraggingProperty);
            CreateTwoWayParentBehaviorBinding(ObjectManipulationBehavior.IsInertiaEnabledProperty, IsInertiaEnabledProperty);
        }

        #endregion

        #region DragDrop Handling

        protected void StartDrag(Point point)
        {
        //    #region adorner stuff copied from rotate behavior

        //static Adorner currentAdorner;
        //static AdornerLayer currentAdornerLayer;

        //private static void OnMouseEnter(object sender, MouseEventArgs e)
        //{
        //    ZComponent element = sender as ZComponent;

        //    if (element != null)
        //    {
        //        AdornerLayer layer = AdornerLayer.GetAdornerLayer(element);
        //        if (layer != null)
        //        {
        //            ZObjectRotateAdorner resizeAdorner = new ZObjectRotateAdorner(element);
        //            layer.Add(resizeAdorner);
        //        }
        //    }
        //}

        //private static void OnMouseLeave(object sender, MouseEventArgs e)
        //{
        //    UIElement element = sender as UIElement;
        //    ZComponent comp = element as ZComponent;
        //    if (comp != null)
        //    {
        //        AdornerLayer layer = AdornerLayer.GetAdornerLayer(comp);
        //        if (layer != null)
        //        {
        //            currentAdornerLayer = layer;
        //            var rotateAdorners = layer.GetAdorners(comp).OfType<ZObjectRotateAdorner>();
        //            foreach (ZObjectRotateAdorner rotateAdorner in rotateAdorners)
        //            {
        //                if (rotateAdorner.AdornedElement == comp)
        //                {
        //                    Rect test = new Rect(e.GetPosition(null).X, e.GetPosition(null).Y, comp.Width, comp.Height);
        //                    if (test.Contains(e.GetPosition(null)))
        //                    {
        //                        currentAdorner = rotateAdorner;
        //                        rotateAdorner.MouseLeave += new MouseEventHandler(rotateAdorner_MouseLeave);
        //                        return;
        //                    }
        //                    layer.Remove(rotateAdorner);
        //                }
        //            }
        //        }
        //    }
        //}

        //static void rotateAdorner_MouseLeave(object sender, MouseEventArgs e)
        //{
        //    currentAdornerLayer.Remove(currentAdorner);
        //}

        //#endregion
            ParentBehavior.RaiseDragChangedEvent(point);
        }

        protected void FinishDrag(Point point)
        {
            ParentBehavior.RaiseDragFinishedEvent(point);
        }

        protected void FinishDrag(FrameworkElement element, Point point)
        {
            ParentBehavior.RaiseDragFinishedEvent(element, point);
        }

        protected void ChangeDrag(Point point)
        {
            ParentBehavior.RaiseDragChangedEvent(point);
        }

        #endregion
    }
}
